import axios, { AxiosError, AxiosInstance, AxiosResponse, Canceler, InternalAxiosRequestConfig, AxiosRequestConfig } from 'axios';
import { errorCodeType } from "@/utils/request/error-code-type";

interface MyCanceler {
    cancel: (message?: string, config?: AxiosRequestConfig, request?: any) => void;
    reason?: string; // 追加的属性，用于存储取消的原因  
    tipsFlag?: boolean;
    // 可以添加其他你需要的属性  
}
interface requestInfo {
    createTime: number
    url: string
    method: string
    cancel: Canceler
}
export class Interceptors {
    requestQueue: {
        [key: string]: requestInfo | any,
    } = {};
    instance: AxiosInstance;
    PUBLICPATH: string = import.meta.env.VITE_PUBLICPATH;
    constructor() {
        this.instance = axios.create({
            // 你的api地址 将自动加在 `url` 前面，除非 `url` 是一个绝对 URL。
            // 这里的话我的baseURL是存放在项目环境变量文件中
            // vite获取env环境变量的方式是import.meta.env
            // baseURL: import.meta.env.VITE_BASE_URL,
            // 请求超时的毫秒数(0 表示无超时时间)
            // timeout: import.meta.env.VITE_REQUEST_TIMEOUT,
            
        });
        this.init();
    }
    init() {
        // 添加请求拦截器
        this.instance.interceptors.request.use(
            (config: InternalAxiosRequestConfig) => {
                // 在这里的话你就可以去设置自己的请求头
                // 比如用户登录以后就能拿到一个token 这个token比如格式是data: {token: '*****'}

                //     config.headers['Authorization'] = `Bearer ${data.token}`
                //     config.headers['X-Access-Token'] = data.token

                if (this.PUBLICPATH == 'dev') {
                    config.url = '/'+config.url!
                }
                // 防止一个接口在没有响应之前进行重新提交即重复提交验证，默认不校验 duplicateRequestValidation为true时开启
                if (config.url && config.submitAgainValidation) {
                    this.removeRequestQueue(config)
                    this.addRequestQueue(config)
                }
                return config;
            },
            (error) => {
                // 对请求错误做些什么 直接抛出错误
                Promise.reject(error)
            }
        );
        // 添加响应拦截器
        this.instance.interceptors.response.use((response: AxiosResponse) => {
            // 在这里的话你就可以去处理你响应成功的自定义逻辑

            // 根据后端返回的code值。比如约定的是20000代表登录过期
            // const res: any = response.data // 获取响应值
            // if (res.code === 20000) {
            //     // 清楚token 跳转登录页面
            // }

            // 比如10000表示请求成功，约定40000~50000不做拦截
            // const filterCode = Math.abs(parseInt(res.code)) >= 40000 && Math.abs(parseInt(res.code)) < 50000
            // if (res.code !== 10000 && !filterCode) {
            //     // 这里去处理请求失败的逻辑
            // } else {
            //     return response.data
            // }

            this.removeRequestQueue(response.config)
            return response.data;
        }, (error: AxiosError) => {
            if (!this.myCanceler.tipsFlag) return Promise.reject(error)
            // 判断重复提交
            let message: string = this.myCanceler.reason || error.message
            if (message.includes("timeout of")) {
                message = "系统接口请求超时"
                this.removeOverTimeRequest()
            } else if (error.response?.status) {
                message = errorCodeType(error.response?.status)
            }
            ElMessage({
                type: 'error',
                showClose: true,
                message,
                duration: 3 * 1000
            })
            return Promise.reject(error);
        });
    }
    // 创建一个函数来创建带有自定义属性的取消令牌源  
    createMyCanceler(): MyCanceler {
        const source = axios.CancelToken.source();
        return {
            cancel: source.cancel,
            reason: undefined,
        };
    }
    myCanceler: MyCanceler = this.createMyCanceler()
    private addRequestQueue(config: InternalAxiosRequestConfig) {
        let reqUrl: string = config.url!
        // 如果正在请求中存在路径一样方法一样的情况，就直接取消请求
        if(this.requestQueue.hasOwnProperty(reqUrl)){
            let p = this.requestQueue[reqUrl]
            if (p.url === config.url && p.method === config.method && config.submitAgainValidation) {
                config.cancelToken = new axios.CancelToken((cancel: Canceler) => {
                    this.myCanceler.tipsFlag = config.submitAgainTipFlag || false
                    let tips = config.submitAgainTip || "频繁请求！"
                    this.myCanceler.cancel = cancel;
                    this.myCanceler.cancel(tips)
                })
            }else{
                config.cancelToken = new axios.CancelToken((cancel: Canceler) => {
                    this.requestQueue[reqUrl]={
                        url: reqUrl!,
                        method: config.method!,
                        cancel,
                        createTime: Date.now()
                    }  
                })
            }
        }else{
            config.cancelToken = new axios.CancelToken((cancel: Canceler) => {
                this.requestQueue[reqUrl]={
                    url: reqUrl!,
                    method: config.method!,
                    cancel,
                    createTime: Date.now()
                }
            })
        }
    }
    private removeRequestQueue(target: InternalAxiosRequestConfig) {
        let reqUrl = target.url || ''
        if(this.requestQueue.hasOwnProperty(reqUrl)){
            let p = this.requestQueue[reqUrl]
            if (p.url === target.url && p.method === target.method && p.createTime && (Date.now() - p.createTime > (target.submitAgainTime || 0))) {
                delete this.requestQueue[reqUrl]
            }
        }
    }
    private removeOverTimeRequest() {
        const nowDate = Date.now()
        for (let key in this.requestQueue) {
            if (this.requestQueue.hasOwnProperty(key)) { // 确保key是对象自身的属性
              const { createTime } = this.requestQueue[key]
                const time = nowDate - createTime
                if (time >= (import.meta.env.VITE_APP_TIMEOUT || 10000)) {
                    delete this.requestQueue[key]
                }
            }
          }
    }
    // 返回一下
    getInterceptors() {
        return this.instance;
    }
}